/* ***** BEGIN LICENSE BLOCK *****
 * Version: MPL 1.1
 *
 * The contents of this file are subject to the Mozilla Public License Version
 * 1.1 (the "License"); you may not use this file except in compliance with
 * the License. You may obtain a copy of the License at
 * http://www.mozilla.org/MPL/
 *
 * Software distributed under the License is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 * for the specific language governing rights and limitations under the
 * License.
 *
 * The Original Code is Info Cram 6000.
 *
 * The Initial Developer of the Original Code is
 * Jiří Mašek.
 * Portions created by the Initial Developer are Copyright (C) 2010
 * the Initial Developer. All Rights Reserved.
 *
 * Contributor(s):
 *
 * ***** END LICENSE BLOCK ***** */

/* ************************************************************************** *
 * ********************************** GUI *********************************** *
 * ************************************************************************** */

/**
 * Obslouží událost <code>onClick</code> elementu <code>tree</code>.
 *
 * @param event     událost
 */
infocram.gui.onClick = function(event) {
    var _tree = this._parent.tree;
    var _editor = this._parent.editor;
    var _name = this._parent.editor.name;
    var _area = this._parent.editor.area;
    var _url = this._parent.editor.url;
    var _read = this._parent.editor.read;
    var _use = this._parent.editor.widgetUse;
    var _attach = this._parent.editor.attach;

    var tree = _tree.get();

    if (event.button == 2 && (tree.currentIndex != 0 || this.editing != this.DEF)) {
        //var currentItem = tree.contentView.getItemAtIndex(tree.currentIndex);
        var editor = _editor.get();
        var name = _name.get();
        var area = _area.get();
        var url = _url.get();
        var read = _read.get();
        var use = _use.get();
        var attach = _attach.get();



        // restoring editor panel

        var hbox = editor.childNodes[0];

        hbox.childNodes[0].hidden = false;

        var vbox = hbox.childNodes[1];

        vbox.childNodes[1].hidden = false;
        vbox.childNodes[2].hidden = false;
        vbox.childNodes[3].hidden = false;

        url.setAttribute("readonly", true);

        var urlUse = document.getElementById("url-use");

        urlUse.hidden = true;

        var urlEdit = document.getElementById("url-edit");

        urlEdit.hidden = false;

        //

        if (tree.currentIndex == 0 && this.editing == this.SELECT) {
            hbox.childNodes[0].hidden = true;

            vbox.childNodes[1].hidden = true;
            vbox.childNodes[2].hidden = true;
            vbox.childNodes[3].hidden = true;

            url.removeAttribute("readonly");

            urlUse.hidden = false;

            urlEdit.hidden = true;
        }








        // naplneni hodnotami

        name.value = this.getColumn("name");
        area.value = this.getColumn("area");
        url.value = this.getColumn("url");

        // read

        var index = 0;

        for (var i = 0; i < read.itemCount; i++) {
            if (read.getItemAtIndex(i).value == this.getColumn("read")) {
                index = i;
                break;
            }
        }

        read.selectedIndex = index;

        // use

        index = 0;

        for (i = 0; i < use.itemCount; i++) {
            if (use.getItemAtIndex(i).value == this.getColumn("use")) {
                index = i;
                break;
            }
        }

        use.selectedIndex = index;

        // attach

        index = 0;

        for (i = 0; i < attach.itemCount; i++) {
            if (attach.getItemAtIndex(i).value == this.getColumn("attach")) {
                index = i;
                break;
            }
        }

        attach.selectedIndex = index;

        // https://developer.mozilla.org/en/XUL_Tutorial/Tree_Box_Objects

        var nameOffset = {
            x: {},
            y: {},
            width: {},
            height: {},
            part: {}
        }

        tree.boxObject.getCoordsForCellItem(tree.currentIndex, tree.columns.getNamedColumn("tree-col-name"), nameOffset.part, nameOffset.x, nameOffset.y, nameOffset.width, nameOffset.height);

        // https://developer.mozilla.org/en/XUL_Tutorial/Tree_Box_Objects

        var areaOffset = {
            x: {},
            y: {},
            width: {},
            height: {},
            part: {}
        }

        tree.boxObject.getCoordsForCellItem(tree.currentIndex, tree.columns.getNamedColumn("tree-col-area"), areaOffset.part, areaOffset.x, areaOffset.y, areaOffset.width, areaOffset.height);

        name.style.width = (areaOffset.x.value - nameOffset.x.value - 8) + "px";

        editor.openPopup(tree, "overlap", nameOffset.x.value - 15, nameOffset.y.value + 12, false, false);
    }
}

/**
 * Obslouží událost <code>onSelect</code> elementu <code>tree</code>.
 */
infocram.gui.onSelect = function() {
    this.refresh();
}

/**
 * Vrátí XUL element tree.
 *
 * @return  XUL element tree
 */
infocram.gui.get = function() {
    var _parent = this._parent;

    return document.getElementById(_parent.TREE);
}

/**
 * Vytvoří nový uzel, jehož rodičem bude uzel definovaný indexem.
 *
 * @param index     index uzlu
 * @param selector  text nového uzlu
 * @param name
 * @param url
 * @param read
 * @param use
 * @param attach
 */
infocram.gui.addNode = function(index, selector, name, url, read, use, attach) {
    var tree = this.get();

    var treeItem = createElement("treeitem");

    var treeRow = createElement("treerow");

    treeItem.appendChild(treeRow);

    // * NAME *******************************
    var treeCell = createElement("treecell");

    if (name == undefined || name == "") {
        name = "child";
    }

    var names = this.getChildNames(index);

    var num;

    for (var i = 0; i < names.length; i++) {
        var matches = names[i].match(new RegExp("^" + name + "([0-9]+)?$"));

        if (matches) {

            if (matches[1] == undefined) {
                if (num == undefined) {
                    num = 0;
                }
            } else {
                if (num < parseInt(matches[1])) {
                    num = parseInt(matches[1]);
                }
            }
        }
    }
        
    if (num != undefined) {
        name = name + (++num);
    }
        
    treeCell.setAttribute("label", name);

    treeRow.appendChild(treeCell);

    // * AREA *******************************
    treeCell = createElement("treecell");

    if (selector != undefined) {
        treeCell.setAttribute("label", selector);
    }

    treeRow.appendChild(treeCell);

    // * URL ********************************
    treeCell = createElement("treecell");

    if (url != undefined) {
        if ((typeof url) == "object") {
            treeCell.setAttribute("label", JSON.stringify(url));
        } else {
            treeCell.setAttribute("label", url);
        }
    }

    treeRow.appendChild(treeCell);

    // * READ *******************************
    treeCell = createElement("treecell");

    if (read != undefined) {
        treeCell.setAttribute("label", read);
    }

    treeRow.appendChild(treeCell);

    // * USE ********************************
    treeCell = createElement("treecell");

    if (use != undefined) {
        treeCell.setAttribute("label", use);
    }

    treeRow.appendChild(treeCell);

    // * ATTACH *****************************
    treeCell = createElement("treecell");

    if (attach != undefined) {
        treeCell.setAttribute("label", attach);
    }

    treeRow.appendChild(treeCell);

    // pridani do stromu

    var currentItem = tree.contentView.getItemAtIndex(index);

    var treeChildren = currentItem.getElementsByTagName("treechildren")[0];

    if (treeChildren == undefined) {
        treeChildren = createElement("treechildren");

        currentItem.appendChild(treeChildren);
    }

    currentItem.setAttribute("container", "true");
    currentItem.setAttribute("open", "true");
    
    treeChildren.appendChild(treeItem);
}

/**
 *
 */
infocram.gui.addChild = function() {
    var tree = this.get();

    if (tree.currentIndex == -1) {
        tree.currentIndex = 0;
    }

    this.addNode(tree.currentIndex, undefined, "child");

    tree.currentIndex++;

    tree.view.selection.select(tree.currentIndex);
}

/**
 * Odstrání definovaný uzel stromu a všechny jeho potomky.
 *
 * @param index     index uzlu
 */
infocram.gui.removeNode = function(index) {
    var tree = this.get();

    var currentItem = tree.contentView.getItemAtIndex(index);

    var treeChildren = currentItem.parentNode;

    treeChildren.removeChild(currentItem);

    if (treeChildren.childNodes.length == 0) {
        var treeItem = treeChildren.parentNode;

        treeItem.removeChild(treeChildren);

        if (treeItem.tagName.toLowerCase() == "treeitem") {
            treeItem.setAttribute("container", "false");
        }
    }
}

/**
 *
 */
infocram.gui.remove = function() {
    var tree = this.get();

    var index = tree.currentIndex

    if (index > 0) {
        this.removeNode(index);
    }
}

/**
 * Odstrání všechny uzely stromu.
 */
infocram.gui.removeAll = function() {
    var tree = this.get();

    var root = tree.contentView.getItemAtIndex(0);

    var treeChildren = root.getElementsByTagName("treechildren")[0];

    if (treeChildren != undefined) {
        root.removeChild(treeChildren);
    }

    this.editColumn(0, "name", "");
    this.editColumn(0, "area", "");
    this.editColumn(0, "url", "");
    this.editColumn(0, "read", "");
    this.editColumn(0, "use", "");
    this.editColumn(0, "attach", "");
}

/**
 * Změní obsah defnovaného uzlu.
 *
 * @param index     index uzlu
 * @param column    nazev sloupecku
 * @param value      text uzlu
 */
infocram.gui.editColumn = function(index, column, value) {
    var tree = this.get();

    tree.view.setCellText(index, tree.columns.getNamedColumn("tree-col-" + column), value);
}

/**
 * Vrátí obsah defnovaného...
 *
 * @param column    nazev sloupecku
 * @param index     index uzlu
 * @return
 */
infocram.gui.getColumn = function(column, index) {
    var tree = this.get();

    if (index == undefined) {
        index = tree.currentIndex == -1 ? 0 : tree.currentIndex;
    }

    return tree.view.getCellText(index, tree.columns.getNamedColumn("tree-col-" + column));
}

/**
 * Vrátí pole hodnot defnovaného...
 *
 * @param index
 * @return
 */
infocram.gui.getChildNames = function(index) {
    var tree = this.get();

    var treechildren = tree.view.getItemAtIndex(index != undefined ? index : tree.currentIndex).getElementsByTagName("treechildren")[0];

    var val = new Array();

    if (!treechildren) {
        return val;
    }

    for (var i = 0; i < treechildren.childNodes.length; i++) {
        val.push(treechildren.childNodes[i].getElementsByTagName("treerow")[0].childNodes[0].getAttribute("label"));
    }

    return val;
}

/**
 * Vrátí kontext zadaného uzlu stromu. Není-li uzel zadán, je vrácen kontext
 * aktuálně vybraného uzlu.
 *
 * @param index             index uzlu
 * @param inclSelected      <code>true</code>, má-li být do kontextu zahrnut
 *                          i výchozí uzel, nepovinný argument
 * @return                  kontext
 */
infocram.gui.getContext = function(index, inclSelected) {
    var tree = this.get();

    if (index == undefined) {
        index = tree.currentIndex;
    }

    var context = inclSelected ? this.getColumn("area", index) : "";

    if (index != -1) {
        while (this.getColumn("url", index) == ""
                && (index = tree.view.getParentIndex(index)) > -1) {
                
            context = this.getColumn("area", index) + " " + context;
        }
    } else {
        context = "";
    }

    return trim(context);
}

/**
 *
 * @return
 */
infocram.gui.getPath = function() {
    var tree = this.get();

    var current;
    var path = new Array();

    if ((current = tree.currentIndex) > 0) {
        do {
            path.unshift(this.getColumn("name", current));
        } while ((current = tree.view.getParentIndex(current)) > 0);
    }

    return path;
}

/**
 *
 *
 * @return
 */
infocram.gui.getJSON = function(treeChildren) {

    if (treeChildren == undefined) {
        var tree = this.get();

        treeChildren = tree.getElementsByTagName("treechildren")[0];
        
    }

    var json = { };

    if (treeChildren != undefined && treeChildren.childNodes.length > 0) {
        for (var i = 0; i < treeChildren.childNodes.length; i++) {
            var treeItem = treeChildren.childNodes[i];

            var treeRow = treeItem.getElementsByTagName("treerow")[0];

            var name = treeRow.childNodes[0].getAttribute("label");

            //******************************** NAME ********************************

            json[name] = {};

            //******************************** AREA ********************************

            var area = treeRow.childNodes[1].getAttribute("label");

            if (area != "") {
                json[name]["area"] = area;
            }

            //********************************* URL ********************************

            var url = treeRow.childNodes[2].getAttribute("label");

            if (url != "") {
                try {
                    var urlJSON = JSON.parse(url);

                    json[name]["url"] = urlJSON;
                } catch (exception) {
                    json[name]["url"] = url;
                }
            }

            //******************************** READ ********************************

            var read = treeRow.childNodes[3].getAttribute("label");

            if (read != "") {
                json[name]["read"] = read;
            }

            //********************************* USE ********************************

            var use = treeRow.childNodes[4].getAttribute("label");

            if (use != "") {
                json[name]["use"] = use;
            }

            //******************************* ATTACH *******************************

            var attach = treeRow.childNodes[5].getAttribute("label");

            if (attach != "") {
                json[name]["attach"] = attach;
            }

            //******************************* SELECT *******************************

            var treeChild = treeItem.getElementsByTagName("treechildren")[0];

            if (treeChild != undefined && treeChild.childNodes.length > 0) {
                json[name]["select"] = this.getJSON(treeChild);
            }
        }
    }

    return json;
}

/**
 *
 *
 * @param elem
 */
infocram.gui.showBox = function(elem) {
    this.clearBox();

    this.borderElems = [];

    var d, i;

    for (i = 0; i < 4; i++)
    {
        d = document.createElementNS("http://www.w3.org/1999/xhtml", "div");

        d.className = "infocrambox"
        d.style.display = "none";
        d.style.position = "absolute";
        d.style.height = "0px";
        d.style.width = "0px";
        d.style.zIndex = "65536";

        d.style.background = "#000";
        d.style.opacity = ".5";

        d.autopagerSelectorLabel = true; // mark as ours

        this.borderElems[i] = d;
    }

    var doc = elem.ownerDocument;
    if (!doc || !doc.body)
        return;

    this.selectedElem = elem;

    for (i = 0; i < 4; i++) {
        try {
            doc.adoptNode(this.borderElems[i]);
        }
        catch (e) {
        // Gecko 1.8 doesn't implement adoptNode, ignore
        }
        doc.body.appendChild(this.borderElems[i]);
    }

    var currentDocument = aardvarkUtils.currentDocument();

    var elements = currentDocument.getElementsByTagName("*");

    var width = 0;

    for (i = 0; i < elements.length; i++) {
        if (width < elements[i].offsetWidth) {
            width = elements[i].offsetWidth;
        }
    }

    var pos = getPos(elem);

    this.borderElems[0].style.left
    = this.borderElems[1].style.left
    = this.borderElems[2].style.left
    = "0px";
    this.borderElems[3].style.left = (pos.x + elem.offsetWidth) + "px";

    this.borderElems[0].style.width
    = this.borderElems[1].style.width
    = (currentDocument.body.offsetWidth > width ? currentDocument.body.offsetWidth : width) + "px";
    this.borderElems[2].style.width = (pos.x) + "px";
    this.borderElems[3].style.width = ((currentDocument.body.offsetWidth > width ? currentDocument.body.offsetWidth : width) - (pos.x + elem.offsetWidth)) + "px";

    this.borderElems[0].style.height = (pos.y) + "px";
    this.borderElems[1].style.height = ((currentDocument.body.offsetHeight > currentDocument.documentElement.clientHeight ? currentDocument.body.offsetHeight : currentDocument.documentElement.clientHeight) - (pos.y + elem.offsetHeight)) + "px";
    this.borderElems[2].style.height
    = this.borderElems[3].style.height
    = (elem.offsetHeight) + "px";

    this.borderElems[0].style.top = "0px";
    this.borderElems[2].style.top
    = this.borderElems[3].style.top
    = (pos.y) + "px";
    this.borderElems[1].style.top = (pos.y + elem.offsetHeight) + "px";

    this.borderElems[0].style.display
    = this.borderElems[1].style.display
    = this.borderElems[2].style.display
    = this.borderElems[3].style.display
    = "";
}

/**
 *
 */
infocram.gui.clearBox = function() {
    for (var i = 0; i < this.borderElems.length; i++) {
        if (this.borderElems[i].parentNode) {
            this.borderElems[i].parentNode.removeChild(this.borderElems[i]);
        }
    }
}

/**
 *
 */
infocram.gui.clearSelection = function() {
    var tree = this.get();

    tree.currentIndex = -1;

    tree.view.selection.clearSelection();

    this.clearBox();
}

/**
 *
 */
infocram.gui.hide = function() {
    var currentDocument = aardvarkUtils.currentDocument();

    var selected = Sizzle(".bpsel", currentDocument);

    for (var i in selected) {
        jQuery(selected[i]).removeClass("bpsel");
    }
}

/**
 *
 *
 * @param selected
 */
infocram.gui.highlight = function(selected) {
    this.hide();

    var currentDocument = aardvarkUtils.currentDocument();

    if (currentDocument.getElementById("bpstyle") == null) {
        var style = currentDocument.createElement('style');

        style.setAttribute("id", "bpstyle");
        style.innerHTML = ".bpsel { background: GreenYellow; }";

        var head = currentDocument.getElementsByTagName('head')[0];

        if (head) {
            head.appendChild(style);
        } else {
            currentDocument.body.appendChild(style);
        }
    }

    try {
        for (var i in selected) {
            jQuery(selected[i]).addClass("bpsel");
        }
    } catch (exception) {}
}

/**
 *
 */
infocram.gui.refresh = function() {
    var context = this.getContext() + " " + this.getColumn("area");

    if (context != "") {
        var currentDocument = aardvarkUtils.currentDocument();

        var selected = Sizzle(context, currentDocument);

        this.highlight(selected);

        this.showBox(selected[0]);
    }
}

/**
 *
 *
 * @param json
 * @param parent
 * @param tree
 */
infocram.gui.display = function(json, parent, tree) {
    var _tree = this._parent.tree;

    if (parent == undefined) {
        this.removeAll();

        this.editColumn(0, "name", this.editing);

        switch (this.editing) {
            case this.SELECT:
                this.editColumn(0, "url", _tree.url);
                break;
            case this.URL:
                if (json.area) {
                    this.editColumn(0, "area", json.area);
                }
                
                if (json.url) {
                    this.editColumn(0, "url", JSON.stringify(json.url));
                }
                
                if (json.read) {
                    this.editColumn(0, "read", json.read);
                }
                
                if (json.use) {
                    this.editColumn(0, "use", json.use);
                }
                
                if (json.attach) {
                    this.editColumn(0, "attach", json.attach);
                }

                json = json.select;
        }

        parent = 0;
    }

    if (tree == undefined) {
        tree = this.get();
    }

    for (var child in json) {
        this.addNode(parent, json[child].area, child, json[child].url, json[child].read, json[child].use, json[child].attach);

        if (json[child].select) {
            this.display(json[child].select , tree.view.rowCount - 1, tree);
        }
    }
}

/**
 *
 */
infocram.gui.saveEdited = function() {
    var _tree = this._parent.tree;

    switch (this.editing) {
        case this.SELECT:
            var json = this.getJSON();
            _tree.url = json.select.url;
            _tree.select = json.select.select;
            break;
        case this.URL:
            var node = _tree;
            for (var i = 0; i < this.path.length; i++) {
                for (var j = 0; j < this.path[i].length; j++) {
                    if (i == 0 && j == 0) {
                        switch (this.area) {
                            case this.SELECT:
                                node = node.select;
                                break;
                            case this.DEF:
                                node = node.def;
                                break;
                        }
                    } else {
                        node = node.select;
                    }

                    node = node[this.path[i][j]];

                    if (i != this.path.length - 1 || j != this.path[i].length - 1) {
                        node = node.url;
                    }
                }
            }
            var url = this.getJSON().url;
            if (isEmpty(url)) {
                node.url = undefined;
            } else {
                node.url = url;
            }
            break;
        case this.DEF:
            _tree.def = this.getJSON().def.select;
            break;
    }
}

/**
 *
 */
infocram.gui.editSelect = function() {
    var _tree = this._parent.tree;

    this.path = new Array();

    this.area = this.SELECT;
    this.editing = this.SELECT;

    this.display(_tree.select);
}

/**
 *
 */
infocram.gui.editDef = function() {
    var _tree = this._parent.tree;

    this.path = new Array();

    this.area = this.DEF;
    this.editing = this.DEF;

    this.display(_tree.def);
}

/**
 *
 * @param button
 */
infocram.gui.switchArea = function(button) {
    this.saveEdited();

    document.getElementById("breadcrumbs").hidden = true;

    if (this.editing == this.DEF) {
        button.label = "Edit Definition";

        this.editSelect();
    } else {
        button.label = "Edit Select";

        this.editDef();
    }
}

/**
 *
 *
 * @param path
 */
infocram.gui.editURL = function(path) {
    var _editor = this._parent.editor;

    var editor = _editor.get();

    this.saveEdited();

    this.editing = this.URL;
    
    this.path.push(path);

    editor.hidePopup();

    this.displayURL();
}

/**
 *
 */
infocram.gui.displayURL = function() {
    var _tree = this._parent.tree;

    var path = this.area;
    
    var node = _tree;

    for (var i = 0; i < this.path.length; i++) {
        for (var j = 0; j < this.path[i].length; j++) {
            if (i == 0 && j == 0) {
                switch (this.area) {
                    case this.SELECT:
                        node = node.select;
                        break;
                    case this.DEF:
                        node = node.def;
                        break;
                }
            } else {
                node = node.select;
            }

            path += " " + this.path[i][j];

            node = node[this.path[i][j]];

            if (i != this.path.length - 1 || j != this.path[i].length - 1) {
                node = node.url;
            }
        }

        if (i != this.path.length - 1) {
            path += " url";
        }
    }


    document.getElementById("path").value = path;
    document.getElementById("breadcrumbs").hidden = false;

    this.display(node.url);
}

/**
 *
 */
infocram.gui.back = function() {
    this.saveEdited();

    this.path.pop();

    if (this.path.length > 0) {
        this.displayURL();
    } else {
        document.getElementById("breadcrumbs").hidden = true;

        switch (this.area) {
            case this.SELECT:
                this.editSelect();
                break;
            case this.DEF:
                this.editDef();
                break;
        }
    }
}

